package com.alinesno.cloud.base.boot.service.impl;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.lang.exception.RpcServiceRuntimeException;
import javax.transaction.Transactional;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.Service;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoFilepatternException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.alinesno.cloud.base.boot.entity.ManagerApplicationEntity;
import com.alinesno.cloud.base.boot.entity.ManagerSourceGenerateEntity;
import com.alinesno.cloud.base.boot.service.IManagerApplicationService;
import com.alinesno.cloud.base.boot.service.IManagerSourceGenerateService;
import com.alinesno.cloud.base.boot.utils.GeneratorSourceTool;
import com.alinesno.cloud.common.core.service.impl.IBaseServiceImpl;
import com.alinesno.cloud.compoment.generate.Generator;
import com.alinesno.cloud.compoment.generate.generator.tools.GitTools;
import com.alinesno.cloud.compoment.generate.generator.tools.JenkinsJobBean;
import com.alinesno.cloud.compoment.generate.generator.tools.JenkinsTools;
import com.alinesno.cloud.compoment.generate.generator.tools.ZipUtils;

import cn.hutool.http.HtmlUtil;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author LuoAnDong
 * @since 2019-04-17 07:44:37
 */
@Service
public class ManagerSourceGenerateServiceImpl extends IBaseServiceImpl<ManagerSourceGenerateEntity, String>
		implements IManagerSourceGenerateService {

	// 日志记录
	private static final Logger log = LoggerFactory.getLogger(ManagerSourceGenerateServiceImpl.class);

	@Autowired
	private IManagerApplicationService managerApplicationService ;

	@Override
	public byte[] generatorCode(String id) throws IOException {
		log.debug("生成代码:{}", id);

		Assert.hasLength(id, "主键不能为空.");
		Date date = new Date();

		ManagerSourceGenerateEntity dto = jpa.findById(id).get();

		// 转义DBURL
		dto.setDbUrl(HtmlUtil.unescape(dto.getDbUrl()));

		String downPath = "/tmp/" + new SimpleDateFormat("yyyy/MM").format(date) + "/" + dto.getFeignServerPath();
		File f = new File(downPath);

		log.debug("downPath:{}", downPath);

		if (f.exists()) {
			FileUtils.forceDelete(f);
		}
		FileUtils.forceMkdir(f);

		Generator g = new GeneratorSourceTool(dto, downPath);
		g.generator(null);
		String targetPath = downPath + "-" + System.currentTimeMillis() + ".zip";
		ZipUtils.toZip(downPath, targetPath, true);

		// 删除临时仓库地址
		FileUtils.forceDelete(f);
		log.debug("删除临时代码成功.");
		
		byte[] data = FileUtils.readFileToByteArray(new File(targetPath));
		
		return data ; 
	}

	@Override
	public String git(String id) throws IOException {
		ManagerSourceGenerateEntity dto = jpa.findById(id).get();
		if(StringUtils.isBlank(dto.getGitRepositoryUrl())) {
			return "ERROR" ; 
		}

		String downPath = "/tmp/git-" + System.currentTimeMillis();
		File file = new File(downPath);
		
		if(!file.exists()) {
			FileUtils.forceMkdir(file);
		}

		log.debug("正在克隆远程仓库.");
		boolean cloneResult = GitTools.cloneGit(dto.getGitRepositoryUrl(), file);
		Assert.isTrue(cloneResult, "远程仓库克隆失败.");

		// 生成代码
		Generator g = new GeneratorSourceTool(dto, downPath);
		g.generator(null);

		log.debug("正在提交代码到远程仓库.");
		boolean commitResult;
		
		try {
			
			commitResult = GitTools.commitAndPush(file, dto.getGitUserName(), dto.getGitPassword(), "代码生成器自动生成【"+dto.getApplicationName()+"】代码并提交项目代码");
			Assert.isTrue(commitResult, "远程仓库提交失败.");
			
		} catch (NoFilepatternException e) {
			log.debug("代码生成路径异常:{}" , e);
			throw new RpcServiceRuntimeException("代码生成路径异常") ; 
		} catch (GitAPIException e) {
			log.debug("代码提交异常:{}" , e);
			throw new RpcServiceRuntimeException("代码提交异常,请确认路径或者账号正确") ; 
		}

		// 删除临时仓库地址
		// FileUtils.forceDelete(file);
		log.debug("删除临时目录代码【{}】成功." , file.getAbsoluteFile());

		return null;
	}

	@Override
	public String jenkins(String id) throws IOException, URISyntaxException {
		
		ManagerSourceGenerateEntity dto = jpa.findById(id).get();
		if(StringUtils.isBlank(dto.getJenkinsUrl())) {
			return "ERROR" ; 
		}

		String credentialsId = "a3164ab0-d246-4d5f-a852-1d775e879599";

		JenkinsJobBean bean = new JenkinsJobBean();
		bean.setCredentialsId(credentialsId);
		bean.setDescription(dto.getApplicationName());
		bean.setDocker(dto.isDockerProject());
		bean.setGitBranch("master"); // 默认master节点
		
		bean.setGitUrl(dto.getGitRepositoryUrl()) ; 
		bean.setJobName(dto.getJenkinsJobname()) ;

		String mvnGoals = "clean package spring-boot:repackage -U ";
		if (bean.isDocker()) {
			mvnGoals += "docker:build ";
		}
		bean.setGoals(mvnGoals);

		String url = dto.getJenkinsUrl() ; 
		String username = dto.getJenkinsUserName() ; 
		String password = dto.getJenkinsPassword() ; 

		JenkinsTools.buildMavenJob(bean, url, username, password);
		
		return bean.getJobName() ; 
	}

	@Transactional
	@Override
	public Map<String, String> projectAutoBuild(ManagerApplicationEntity app, ManagerSourceGenerateEntity source) {

		Assert.notNull(app , "应用不能为空.");
		Assert.notNull(source, "源码应用不能为空.");
		
		Map<String, String> resultMap = new HashMap<String, String>() ; 
		
		app = managerApplicationService.save(app) ; 
		source = jpa.save(source) ; 
		
		try {
			
			if(StringUtils.isNotBlank(source.getGitRepositoryUrl())) {
				git(source.getId()) ; 
				resultMap.put("GIT_PATH", source.getGitRepositoryUrl()) ; 
			}
			
			if(StringUtils.isNotBlank(source.getJenkinsUrl())) {
				jenkins(source.getId()) ;
				resultMap.put("JENKINS_PATH", source.getJenkinsUrl()) ; 
				resultMap.put("DOCKER_PATH", source.getJenkinsUrl()) ; 
			}
		
			
		} catch (IOException e) {
			log.debug("文件读取异常:{}" , e);
			
			throw new RpcServiceRuntimeException("文件读取异常.") ; 
		} catch (URISyntaxException e) {
			log.debug("请求链接地址错误:{}" , e);
			
			throw new RpcServiceRuntimeException("请求链接地址错误") ; 
		} 
		
		return null;
	}

}
